package com.weic.easycache.http.proxy;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;

import org.apache.http.util.ByteArrayBuffer;

import com.weic.easycache.http.Http;

import android.util.Log;

class HttpStreamJoiner extends Thread {
	public static final boolean LOG = false;
	public static final String LOG_TAG = "[HttpStreamJoiner]";
	public String MSG;
	public static String encoding = "utf-8";

	final String[] mHeaders;
	final Socket mClientSocket;
	Socket mRemoteSocket;
	String mRemoteHost;
	int mRemotePort;

	String mRedirectUri;

	OutputStream clientOut;
	OutputStreamWriter clientWriter;

	InputStream remoteIn;
	OutputStreamWriter remoteWriter;

	boolean OK = false, redirect = false;

	public HttpStreamJoiner(final Socket socket, String[] headers, String remoteHost, int remotePort) {
		mHeaders = headers;
		mClientSocket = socket;
		mRemoteHost = remoteHost;
		mRemotePort = remotePort;
		setDaemon(true);
	}

	private void initClientOut() throws IOException {
		if(clientOut == null) {
			clientOut = mClientSocket.getOutputStream();
			clientWriter = new OutputStreamWriter(clientOut);
		}
	}
	@Override
	public void run() {
		MSG = currentThread().toString();
		Log.d(LOG_TAG, MSG+"start---------------");
		try {
			initClientOut();

			mRemoteSocket = new Socket(InetAddress.getByName(mRemoteHost), mRemotePort);
			remoteWriter = new OutputStreamWriter(mRemoteSocket.getOutputStream());
			//发送请求
			for(String line : mHeaders) {
				remoteWriter.write(line);
				if(LOG) Log.i(LOG_TAG, MSG+"[send]"+line);
			}
			remoteWriter.flush();
			//不能在此时close()，否则socket同时被关闭
			//remoteWriter.close();

			remoteIn = mRemoteSocket.getInputStream();
			//解析请求
			if(LOG) Log.d(LOG_TAG, MSG+"[response]=================");

			String line = null;
			do {
				/* 这里不能使用BufferedReader.readLine()，否则后面对接流的时候将出错，可能
				 * 是因为BufferedReader缓冲了部分字节，导致对接的时候数据序列没有正常连接。
				 * line = remoteReader.readLine();
				 * line = line==null ? HTTP.CRLF : line+HTTP.CRLF;
				 */
				line = readHeadLine(remoteIn);

				if(LOG) Log.i(LOG_TAG, MSG+"[response]"+line);

				if(redirect) {	//放在前面
					if(line.startsWith(Http.LOCATION)) {
						String redirectURL = line.split(" +")[1].trim();	//去掉结尾的回车
						redirectURL = redirectURL.substring(Http.URL_start.length());
						String hostAdress = redirectURL.substring(0, redirectURL.indexOf("/"));
						int index = hostAdress.indexOf(":");
						if(index>=0) {
							String[] strs = hostAdress.split(":");
							mRemoteHost = strs[0].equals("") ? mRemoteHost : strs[0];
							mRemotePort = Integer.valueOf(strs[1]);
						}else {
							mRemoteHost = hostAdress;
							mRemotePort = 80;
						}
						mRedirectUri = redirectURL.substring(redirectURL.indexOf("/"));
					}
					break;
				}

				//解析请求字符串并转发
				if(line.startsWith(Http.HTTPv)) {
					String[] status = line.split(" +");
					if(LOG) {
						int len = status.length;
						String msg = "";
						for(int i=2; i<len; i++) {
							msg += status[i]+" ";
						}
						msg = msg.trim();
						Log.i(LOG_TAG, MSG+"Code:"+status[1]+", Message:"+msg);
					}
					int code = Integer.valueOf(status[1]);
					if(code == 200) {	//正常返回
						OK = true;
						clientWriter.write(line);
						clientWriter.flush();
						break;	//退出循环并将流写入到客户端
					}else if(code == 302) {	//重定向
						redirect = true;
					}else {
						clientWriter.write(line);
						clientWriter.flush();
						break;	//退出循环并将流写入到客户端
					}
				}
			}while(!line.equals(Http.CRLF));

			if(redirect) {
				//重新组合headers向新主机发送请求
				int len = mHeaders.length;
				for(int i=0; i<len; i++) {
					line = mHeaders[i];
					if(line.startsWith(Http.GET)) {
						line = Http.GET+" "+mRedirectUri+" "+line.split(" +")[2];
						mHeaders[i] = line;
						break;
					}
				}
				/* 这三者无论何种顺序都可以，
				 * 对于客户端，何种关闭顺序都可以，
				 * 而服务端必须先关闭out，否则如果先关闭in，则out无法写出，导致异常。
				 */
				remoteWriter.close();
				remoteIn.close();
				mRemoteSocket.close();
				//递归再来一遍
				OK = false;
				redirect = false;
				run();	//=====================================================
			}else {
				//将流接入到客户端
				joinStream(remoteIn, clientOut);
			}
		}catch(ConnectException e) {
			Log.e(LOG_TAG, MSG+"remote Connect refused!!!!!!!!!!!!!!!!!!!!!");
		}catch(SocketException e) {
			Log.e(LOG_TAG, MSG+"user's Socket closed~~~~~~~~~~~~~~~~~~");
		}catch(IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if(clientWriter != null) clientWriter.close();
				if(clientOut != null) clientOut.close();
				if(remoteWriter != null) remoteWriter.close();
				if(remoteIn != null) remoteIn.close();
				if(mRemoteSocket != null) mRemoteSocket.close();
				mClientSocket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			Log.d(LOG_TAG, MSG+"end---------------");
		}
	}

	private void joinStream(InputStream remotein, OutputStream clientout) throws IOException {
		byte[] buffer = new byte[2048];
		int len = 0;
		if(LOG) Log.d(LOG_TAG, MSG+"[joinStream]start---------");
		while((len = remotein.read(buffer)) != -1) {
			//如果客户端关闭链接，则这里可能抛异常，不过这是正常现在，不影响下一个客户端的链接
			clientout.write(buffer, 0, len);
			if(LOG) Log.i(LOG_TAG, "bytes:"+len);
		}
		if(LOG) Log.d(LOG_TAG, MSG+"[joinStream]end---------");
	}

	private String readHeadLine(InputStream in) throws IOException {
		ByteArrayBuffer bytes = new ByteArrayBuffer(50);

		byte readByte;
		do {
			readByte = (byte) in.read();
			if(readByte != -1) {
				bytes.append(readByte);
			}else {
				if(LOG) Log.i(LOG_TAG, MSG+"[readHeadLine, end,break]readByte:"+readByte);
				break;
			}
		} while (readByte!=10);	//10就是回车符
		return new String(bytes.toByteArray(), encoding);
	}
}
